import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
import store from '@/store'
Vue.use(VueRouter)

//专门做增强的函数
function enhance (target,funcName){
	//第一步：备份一下原始的方法
	const origin = target.prototype[funcName]
	//第二步：修改原始的方法
	target.prototype[funcName] = function(location,okCallback,errCallback){
		// 第三步：追加自己的逻辑
		if(okCallback || errCallback){ //如果使用者传递了成功的回调、失败的回调，那么就直接传递就ok了
			return origin.call(this,location,okCallback,errCallback)
		}else{
			return origin.call(this,location).catch(()=>{})
		}
	}
}

//增强VueRouter原型上的push方法
enhance(VueRouter,'push')
//增强VueRouter原型上的replace方法
enhance(VueRouter,'replace')

const router = new VueRouter({
	mode:'history',
	routes,
	scrollBehavior (to, from, savedPosition) {
		return { y: 0 }
	}
})



// 全局前置守卫
// 判断有没有token
// 如果有token代表已经登录了
// 		判断有没有个人信息
// 				如果有个人信息,放行即可
// 				如果没有个人信息
// 						获取个人信息
// 								获取个人信息成功,放行
// 								获取个人信息失败,清除token,跳转login
// 如果没有token代表没有登录
// 		目前放行
router.beforeEach(async (to, from, next) => {
	let token = store.state.user.token;
	if (token) {
		// 判断有没有个人用户信息,这里不能直接哪 userinfo,因为没有用户信息的时候,userinfo是一个对象
		// let userinfo = store.state.user.userinfo;
		let username = store.state.user.userinfo.name;
		if (username) { // 如果有个人信息放行即可
			next();
		} else { // 没有个人信息,获取个人信息
			try {
				// 获取个人信息
				await store.dispatch('user/getUserInfo');
				// 如果没有报错,证明获取到了用户信息,放行即可
				next();
			} catch (error) {
				console.log('获取用户信息失败', error)
				// 什么情况下会走到 catch 当中
				// 1. 网络错误
				// 2. 接口调成功,但是后端返回失败状态码(没有获取到个人信息) - 模拟token过期
				// next('/login')

				// 网络错误我们没法模拟,错误2我们可以模拟,让store当中存的token不对即可
				// 让token存的不对是模拟 token 过期
				// 怎么办?
				// 清除token,再跳转到login即可

				// 清除token
				store.dispatch('user/clearToken');
				// 然后跳转login
				next('/login')
			}
		}
	} else {
		// 没有登录

		// 这里不能直接跳转login,每次跳转都重新走路由跳转的流程,就会重新经过守卫,守卫中的代码就会重新执行
		// 重新执行,还是没有token,又跳转login,又重新走路由跳转过程,又重新经过守卫,守卫中的代码就会重新执行
		// .....死循环
		// next('/login')

		// 这里【目前】放行,因为首页、搜索页、详情页等并不需要登录就可以查看
		// next()

		// 项目完成,对交易相关、支付相关、个人中心在没有登录的状态下进行拦截
		// 走到当前 else 代表没有token,代表没有登录,此时去需要拦截的页面,拦截住让跳转到登录页面即可
		// if (to.path.includes('/trade') || to.path.includes('/pay') || to.path.includes('/center')) {
		// 	next('/login')
		// } else {
		// 	next();
		// }
		// 优化: 当页面过多的时候,总是放 || 不合适,代码会显得太长而变得臃肿
		// 创建一个黑名单,凡是在这个黑名单的数组中的页面都需要登录
		const blackList = ['/trade', '/pay', '/center']; // 这个变量可以放全局
		// 判断，即将去的页面是不是在黑名单当中,如果是,那么需要拦截
		const isIntercept = blackList.some(path => to.path.includes(path));
		if (isIntercept) {
			alert('交易、支付、个人中心需要登录才能访问');
			next(`/login?redirect=${ to.path }`)
		} else {
			next()
		}

	}
})






// 全局前置守卫
// router.beforeEach((to, from, next) => {
//   // to 到哪里去,是一个路由对象
// 	// form 从哪里来,是一个路由对象
//   console.log('全局前置守卫 - beforeEach', next);
// 	next(); // 直接调用可以理解为放行,继续往下执行的意思
// 	next(false); // 不放行,呆在这什么都不做,路由页面跳转不走

// 	next('/') // 去首页,重新指定了跳转的路由,【重新再走一遍路由跳转的过程】
// 	next({ path: '/' }) // 去首页,重新指定了跳转的路由,【重新再走一遍路由跳转的过程】
// })






// // 全局前置守卫
// router.beforeEach((to, from, next) => {
//   console.log('全局前置守卫 - beforeEach');
// 	// 注意: 参数三是next,目前只要看到有 next参数,就调用一下,至于是什么意思,后面再说
// 	next(); 
// })
// // 全局解析
// router.beforeResolve((to, from, next) => {
//   console.log('全局解析守卫 - beforeResolve');
// 	next(); 
// })
// // 全局后置
// router.afterEach((to, from) => {
//   console.log('全局后置钩子 - afterEach')
// })


export default router
